﻿/*
 * This software is the confidential and proprietary
 * information of NetBay
 * Such confidential information should not be disclosed
 * NetBay copyright(c) 2010
 */

#region Using
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.ComponentModel;
using Rio.Framework.WCFService.RioWcfServices;

#endregion

namespace Rio.Framework.WCFService 
{
    public class PostManyDocument : IDisposable
    {
        #region Properties
        #endregion

        #region Attributes
        /// <summary>
        /// List of file to Post
        /// </summary>
        private List<FileInfo> m_oFileInfoCollection;
        /// <summary>
        /// Size of one slice document
        /// </summary>
        private long m_lSizeOfSlice;
        /// <summary>
        /// User Id
        /// </summary>
        private long m_lUserId;


        /// <summary>
        /// 
        /// </summary>
        private string m_sDestinationRelativePath;
        /// <summary>
        /// 
        /// </summary>
        private string m_sStoragePath;
        /// <summary>
        /// 
        /// </summary>
        private bool m_bOverwrite;
        #endregion

        #region Events
        /// <summary>
        /// The delagate to handle the 'BeforePostDocument'
        /// </summary>
        /// <param name="p_szOnPostDocument">the file name to post forward the services</param>
        public delegate void BeforePostDocumentEventHandler(string p_szOnPostDocument);

        /// <summary>
        /// Event to notify the progress of Process
        /// </summary>
        public event BeforePostDocumentEventHandler BeforePostDocument;

        public event EventHandler AbortImport;
        public event EventHandler EndOfPost;
        public event EventHandler PostError;
        private BackgroundWorker bw;

        bool m_bIsError = false;

        Action<string> m_oBeforePostDocument = null;
        Action<int, string, ImageRio> m_oOnProgress = null;
        /// <summary>
        /// Fire a 'BeforePostDocument' event to any registered client
        /// </summary>
        /// <param name="p_oOnBeforePostDocument"></param>
        /// <param name="p_szOnPostDocument">the file name to post forward the services</param>
        private void OnBeforePostDocument(Action<string> p_oOnBeforePostDocument, string p_szOnPostDocument)
        {
            lock (this)
            {
                //Logger.Write("(Name<" + FileInfo.Name + "> p_dPercentageDone<" + p_dPercentageDone + "> p_szErrorMessage<" + p_szErrorMessage + ">", Logger.Level.Verbose);
                if (p_oOnBeforePostDocument != null)
                {
                    SmartDispatcher.BeginInvoke(p_oOnBeforePostDocument, p_szOnPostDocument);
                   
                }
                else if (BeforePostDocument != null)
                {
                    BeforePostDocument(p_szOnPostDocument);
                }
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        public PostManyDocument(long p_lUserId, IEnumerable<FileInfo> files, long p_lSizeOfSlice)
        {
            bw = new BackgroundWorker {WorkerSupportsCancellation = true};

            bw.DoWork +=  bw_DoWork;
            bw.RunWorkerCompleted += bw_RunWorkerCompleted;
            
            m_oFileInfoCollection = new List<FileInfo>(files);
            m_lSizeOfSlice = p_lSizeOfSlice;
            m_lUserId = p_lUserId;
        }

        /// <summary>
        /// Post document to the specified path and storage  
        /// </summary>
        /// <param name="p_lUserId">User identifier</param>
        /// <param name="files">List of files to post</param>
        /// <param name="p_lSizeOfSlice">Size of slice</param>
        /// <param name="destinationFullPath">Relative destination on the remote server</param>
        /// <param name="storagePath">Storage path on the remote server</param>
        /// <param name="overwrite">Indicate whether the file must be overwrite if exist</param>
        public PostManyDocument(long p_lUserId, IEnumerable<FileInfo> files, long p_lSizeOfSlice, string destinationFullPath, string storagePath, bool overwrite)
            :this(p_lUserId,files,p_lSizeOfSlice)
        {
            m_sDestinationRelativePath = destinationFullPath;
            m_sStoragePath = storagePath;
            m_bOverwrite = overwrite;
        }
        #endregion

        #region Statics
        #endregion

        #region Publics

        List<Thread> m_oListThread = new List<Thread>();

        /// <summary>
        /// Process a 'PostManyDocument'
        /// </summary>
        public void Do(Action<string> p_oBeforePostDocument = null, Action<int, string, ImageRio> p_oOnProgress = null)
        {

            m_oBeforePostDocument = p_oBeforePostDocument;
            m_oOnProgress = p_oOnProgress;

            if (!bw.IsBusy)
            {
                bw.RunWorkerAsync();
            }
        }


        /// <summary>
        /// Handles the DoWork event of the bw control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            if (m_oFileInfoCollection != null && m_oFileInfoCollection.Count > 0)
            {
                foreach (FileInfo f in m_oFileInfoCollection)
                {
                    if ((bw.CancellationPending == true))
                    {
                        e.Cancel = true;
                        break;
                    }
                    if (!m_bIsError)
                    {
                        try
                        {
                            // Perform a time consuming operation and report progress.
                            OnBeforePostDocument(m_oBeforePostDocument, f.Name);
                            using (PostDocument l_oPostDocument = new PostDocument(Guid.NewGuid(), m_lUserId, f, m_lSizeOfSlice, false, m_sDestinationRelativePath, m_sStoragePath, m_bOverwrite))
                            {
                                m_oListThread.Add(l_oPostDocument.Do(m_oOnProgress));
                            }
                        }catch(Exception)
                        {
                        }
                    }
                }
            }
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if ((e.Cancelled == true))
            {
                if (EndOfPost != null)
                {
                    EndOfPost(this, null);
                }
            }

            else if (!(e.Error == null))
            {
                if (PostError != null)
                {
                    PostError(this, null);
                }
            }

            else
            {
                if (EndOfPost != null)
                {
                    EndOfPost(this, null);
                }
            }
        }

                
        /// <summary>
        /// Stop the current thread
        /// </summary>
        public void StopPost()
        {
            if (bw.WorkerSupportsCancellation == true)
            {
                bw.CancelAsync();
                AbortImport(this, null);
            }
        }

        #endregion

        public void Dispose()
        {
            if (bw != null)
            {
                bw.DoWork -= bw_DoWork;
                bw.RunWorkerCompleted -= bw_RunWorkerCompleted;
                bw = null;
            }
        }
    }
}
